Skip to content

Use assigned workspace tab color for selected sidebar rows - #2569

Closed
lawrencecchen wants to merge 1 commit into
mainfrom
issue-2565-selected-workspace-tab-color
Closed

lawrencecchen wants to merge 1 commit into
mainfrom
issue-2565-selected-workspace-tab-color

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Apr 4, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • use the assigned workspace tab color for the selected sidebar row background when a workspace color is set
  • keep the existing selection highlight fallback for workspaces without a custom color
  • darken overly bright custom colors enough to preserve readable selected-state foreground text in light and dark appearance

Testing

  • not run locally per repo policy

Closes #2565


Summary by cubic

Use each workspace tab’s assigned color for the selected sidebar row, falling back to the current highlight when no custom color is set. Automatically darkens bright custom colors to keep the white selected-state text readable in light and dark modes (closes #2565).

Written for commit 9e7d5f3. Summary will update on new commits.

Summary by CodeRabbit

  • Bug Fixes
    • Enhanced contrast and readability for custom workspace background colors by automatically darkening selections that are too bright to ensure text remains legible.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@vercel

vercel Bot commented Apr 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Apr 4, 2026 0:44am

@coderabbitai

coderabbitai Bot commented Apr 4, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Added color science utilities to compute relative luminance and contrast ratios. Enhanced sidebarSelectedWorkspaceBackgroundNSColor to accept optional custom hex colors, automatically darkening overly bright colors until they meet a 4.5:1 contrast ratio against white. Updated TabItemView to pass custom tab colors to the enhanced function, enabling selected workspace backgrounds to use assigned tab colors instead of default accent colors.

Changes

Cohort / File(s) Summary
Sidebar Selection Color Enhancement
Sources/ContentView.swift
Added color science helpers for luminance and contrast ratio computation. Modified sidebarSelectedWorkspaceBackgroundNSColor to accept optional custom hex colors with automatic brightness adjustment for contrast compliance (threshold 4.5). Updated TabItemView.selectionBackgroundColor to leverage custom tab colors via the enhanced function signature, enabling assigned colors to display in selected state.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A rabbit hops through colors bright,
Adjusting hues to match the light,
When darkness falls too deep and true,
We lighten up to see it through,
Selected workspaces now shine their own,
In contrast-checked and custom-grown! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately captures the main change: using assigned workspace tab colors for selected sidebar rows instead of the hardcoded blue accent.
Description check ✅ Passed The PR description covers the core changes, explains the fallback behavior, and addresses color darkening logic. While testing details are minimal (per repo policy), the summary is substantive and complete.
Linked Issues check ✅ Passed The code changes directly implement all requirements from issue #2565: using assigned tab color for selected state, maintaining blue accent fallback, darkening bright colors, and supporting both light/dark modes.
Out of Scope Changes check ✅ Passed All changes (color-science helpers, custom color derivation, and sidebar row color logic) are directly scoped to implementing the assigned workspace tab color for selected state as specified in issue #2565.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-2565-selected-workspace-tab-color

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
Sources/ContentView.swift (1)

78-138: Consider adding focused regression tests for color-adjustment boundaries.

Given this is behavior-critical UI logic, a few unit tests would help lock in: invalid hex handling, no-custom fallback path, and very bright custom colors meeting the readability threshold.

Also applies to: 177-194

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/ContentView.swift` around lines 78 - 138, Add unit tests covering the
color-adjustment boundaries for the sidebar color helpers: write tests that
exercise sidebarSelectedWorkspaceCustomBackgroundNSColor and
sidebarSelectedWorkspaceReadableBackgroundNSColor (and indirectly
sidebarSelectedWorkspaceRelativeLuminance and
sidebarSelectedWorkspaceContrastRatio) to assert: 1) invalid hex returns nil
(invalid hex handling), 2) absence of a custom color falls back to the expected
behavior/path, and 3) extremely bright input colors are iteratively darkened
until the contrast with white meets the minimumContrast (4.5) — include
assertions on final contrast ratio and that iteration halts within the expected
iteration limit.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Sources/ContentView.swift`:
- Around line 78-138: Add unit tests covering the color-adjustment boundaries
for the sidebar color helpers: write tests that exercise
sidebarSelectedWorkspaceCustomBackgroundNSColor and
sidebarSelectedWorkspaceReadableBackgroundNSColor (and indirectly
sidebarSelectedWorkspaceRelativeLuminance and
sidebarSelectedWorkspaceContrastRatio) to assert: 1) invalid hex returns nil
(invalid hex handling), 2) absence of a custom color falls back to the expected
behavior/path, and 3) extremely bright input colors are iteratively darkened
until the contrast with white meets the minimumContrast (4.5) — include
assertions on final contrast ratio and that iteration halts within the expected
iteration limit.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d81896da-b9ea-40a5-9403-dfaf67427759

📥 Commits

Reviewing files that changed from the base of the PR and between c014f31 and 9e7d5f3.

📒 Files selected for processing (1)
  • Sources/ContentView.swift

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

@greptile-apps

greptile-apps Bot commented Apr 4, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR wires the per-workspace custom color into the sidebar's selected-row background, applying a WCAG-based contrast-darkening loop so that the selected-state text stays readable over bright custom colors. The fallback chain (custom workspace color → user-set sidebar selection color → accent color) is preserved.

Key changes:

  • Four new private helpers implement relative-luminance, contrast-ratio, and iterative darkening (up to 12 passes of 12% black blending) to ensure ≥ 4.5:1 contrast with white.
  • sidebarSelectedWorkspaceBackgroundNSColor is refactored to accept customHex and sidebarSelectionColorHex as parameters instead of reading UserDefaults directly; TabItemView.selectionBackgroundColor now passes tab.customColor through this path.
  • The main logical concern is that the readability loop always measures contrast against NSColor.white, which is only correct when the selected-row label text is actually white. In light-mode appearances the foreground is typically dark, so the contrast target should switch based on colorScheme.
  • The default parameter that reads UserDefaults is never exercised in practice (the sole call site always passes the value explicitly), which may mislead future callers.
  • forceBright is intentionally omitted when resolving the custom color for the background, which differs from other call sites — a comment explaining the reasoning would help maintainability.

Confidence Score: 3/5

Functionally adds the custom color to sidebar selection, but the contrast loop assumes white foreground text, which may produce incorrect behavior in light mode where the foreground is dark.

The core feature logic is sound for dark mode, but the hardcoded white foreground assumption in sidebarSelectedWorkspaceReadableBackgroundNSColor is a real correctness risk for light-mode appearances. Additionally the unused default parameter is a minor maintenance concern. The change is isolated to sidebar rendering and has no side effects on other subsystems.

Sources/ContentView.swift — specifically sidebarSelectedWorkspaceReadableBackgroundNSColor (contrast target) and sidebarSelectedWorkspaceBackgroundNSColor (unused default parameter).

Important Files Changed

Filename Overview
Sources/ContentView.swift Adds workspace custom color to sidebar selected-row background with WCAG contrast adjustment. The contrast check hardcodes NSColor.white as the foreground, which may not be correct in all appearance modes; the default parameter reading UserDefaults is also never exercised in practice.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[selectionBackgroundColor] --> B[sidebarSelectedWorkspaceBackgroundNSColor]
    B --> C{customHex present?}
    C -- Yes --> D[sidebarSelectedWorkspaceCustomBackgroundNSColor]
    D --> E[WorkspaceTabColorSettings.displayNSColor]
    E --> F[sidebarSelectedWorkspaceReadableBackgroundNSColor]
    F --> G{contrast with white < 4.5 AND iter < 12?}
    G -- Yes --> H[blend 12% black]
    H --> G
    G -- No --> I[Return darkened color]
    I --> Z[Use as background]
    C -- No --> J{sidebarSelectionColorHex present?}
    J -- Yes --> K[NSColor hex parse]
    K --> Z
    J -- No --> L[cmuxAccentNSColor]
    L --> Z
Loading

Comments Outside Diff (1)

  1. Sources/ContentView.swift, line 177-196 (link)

    P2 Default parameter reading UserDefaults is never exercised

    The refactored function signature adds a default value that eagerly reads UserDefaults.standard at each call site where the default is applied. However, the single call site in TabItemView.selectionBackgroundColor (lines 13399–13403) always passes the argument explicitly via settings.selectionColorHex. The default is therefore dead code.

    This can mislead future callers into thinking the default is the intended path when it is not. Consider removing the default and making the parameter required to make the intent explicit — or, if the default is meant to remain for convenience, add a comment explaining when callers should rely on it.

Reviews (1): Last reviewed commit: "Use workspace tab color for selected sid..." | Re-trigger Greptile

Comment thread Sources/ContentView.swift
Comment on lines +115 to +125
// Keep the assigned hue, but darken overly bright custom colors until the
// existing white selected-state foreground remains readable.
while sidebarSelectedWorkspaceContrastRatio(between: adjusted, and: NSColor.white) < minimumContrast,
iteration < 12 {
guard let darkened = adjusted.blended(withFraction: 0.12, of: .black) else { break }
adjusted = darkened.usingColorSpace(.sRGB) ?? darkened
iteration += 1
}

return adjusted
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Hardcoded white foreground may produce wrong contrast in light mode

The readability loop always measures contrast against NSColor.white:

while sidebarSelectedWorkspaceContrastRatio(between: adjusted, and: NSColor.white) < minimumContrast,

This is only correct when the selected-row label text is actually white. In light-mode appearances, the sidebar's selected-state text is often rendered in a dark color (e.g., .labelColor, which resolves to near-black in light mode). Darkening a mid-range color to achieve 4.5:1 against white when the real foreground is dark would overshoot — making the background needlessly dark in light mode.

Consider passing colorScheme into sidebarSelectedWorkspaceReadableBackgroundNSColor and using NSColor.white in dark mode but NSColor.black (or a sampled label color) in light mode so the contrast target matches the actual rendered foreground.

Comment thread Sources/ContentView.swift
Comment on lines +109 to +113

private func sidebarSelectedWorkspaceReadableBackgroundNSColor(_ color: NSColor) -> NSColor {
let minimumContrast: CGFloat = 4.5
var adjusted = color.usingColorSpace(.sRGB) ?? color
var iteration = 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 forceBright omitted — potential visual inconsistency in leftRail mode

WorkspaceTabColorSettings.displayNSColor is called here without forceBright:

guard let color = WorkspaceTabColorSettings.displayNSColor(
    hex: hex,
    colorScheme: colorScheme
) else {

Every other call site in TabItemView passes forceBright: activeTabIndicatorStyle == .leftRail (lines 13437–13440, 13445–13448). This means the selection background in leftRail mode starts from the base (un-brightened) color, while the left-rail indicator and the color swatch both use the brightened version. The contrast-darkening loop will then operate on a dimmer starting color and may produce a slightly different shade than expected. If this is intentional (avoiding double-brightness before darkening), a comment explaining the decision would help.

@austinywang

Copy link
Copy Markdown
Contributor

Closing this PR because it was created from the wrong GitHub identity. Replacement: #2570.

@austinywang austinywang closed this Apr 4, 2026

This branch was successfully deployed

1 active deployment
Preview — 9e7d5f37 Deployed Apr 3, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Selected workspace background should use assigned tab color

2 participants